/**
 * @name ReactCarousel
 * @author darcrand
 * @desc 轮播
 * @version 2019-06-22
 */

import React, { Component } from "react"
import PropTypes from "prop-types"

import Fade from "./Fade"
import Slide from "./Slide"
import Navigation from "./Navigation"
import Pagination from "./Pagination"

import img1 from "../images/img001.jpg"
import img2 from "../images/img002.jpg"
import img3 from "../images/img003.jpg"

import "./styles.css"

// 动画过渡时间,由于无法动态设置css,先写死
const TRANSITION_DURATION = 1000

class ReactCarousel extends Component {
    state = {
        curr: 0,
        direction: "forward", // ['forward','backward'] 通过方向来判断需要用哪个过渡动画
        locked: false //动画过渡锁,防止切换频繁
    }

    playTimer = null

    componentDidMount() {
        this.initAutoPlay()
    }

    componentWillUnmount() {
        // 万能禁止卸载组件时,触发setState
        this.setState = (state, cb) => null
        // 清除自动播放计时器
        clearTimeout(this.playTimer)
    }

    onChange = index => {
        if (this.state.locked) {
            return
        }
        this.setState(prevState => ({ curr: index, direction: index > prevState.curr ? "forward" : "backward", locked: true }), this.openLock)
    }

    onPrev = () => {
        if (this.state.locked) {
            return
        }
        this.setState(prevState => {
            const index = backCycle(prevState.curr - 1, this.props.images.length)
            return { curr: index, direction: "backward", locked: true }
        }, this.openLock)
    }

    onNext = () => {
        if (this.state.locked) {
            return
        }
        this.setState(prevState => {
            const index = backCycle(prevState.curr + 1, this.props.images.length)
            return { curr: index, direction: "forward", locked: true }
        }, this.openLock)
    }

    openLock = () => {
        const t = setTimeout(() => {
            clearTimeout(t)
            this.setState({ locked: false })
        }, TRANSITION_DURATION)
    }

    initAutoPlay = () => {
        if (!this.props.autoPlay) {
            return
        }

        this.playTimer = setInterval(() => {
            this.onNext()
        }, this.props.interval)
    }

    get renderContent() {
        const { images, effect } = this.props
        const { curr, direction } = this.state

        switch (effect) {
            case "slide":
                return <Slide images={images} curr={curr} direction={direction} />
            default:
                return <Fade images={images} curr={curr} />
        }
    }

    get renderPagenation() {
        const { images, pagination } = this.props
        const { curr } = this.state
        if (pagination && typeof pagination === "boolean") {
            return <Pagination images={images} curr={curr} onChange={this.onChange} />
        }
        if (pagination && typeof pagination === "function") {
            // 如果"pagination"为Function,则传入数据并返回JSX.Element
            return pagination({ images, curr, onChange: this.onChange.bind(this) })
        }
    }

    render() {
        const { width, height, navgation } = this.props

        return (
            <div className="react-carousel_container" style={{ width, height }}>
                {this.renderContent}

                {navgation && <Navigation onPrev={this.onPrev} onNext={this.onNext} />}
                {this.renderPagenation}
            </div>
        )
    }
}

ReactCarousel.propTypes = {
    width: PropTypes.string, //宽度
    height: PropTypes.string, //高度
    effect: PropTypes.oneOf(["fade", "slide", "scale"]), //切换方式
    images: PropTypes.arrayOf(PropTypes.string).isRequired, //图片路径数组
    autoPlay: PropTypes.bool, //是否自动播放
    interval: PropTypes.number, //自动播放时,播放间隔(毫秒)
    navgation: PropTypes.oneOfType([PropTypes.bool]), //是否显示"前进","后退"按钮
    pagination: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]) //是否显示底部"页码"
}

ReactCarousel.defaultProps = {
    width: "100%",
    height: "460px",
    effect: "fade",
    images: [img1, img2, img3],
    autoPlay: false,
    interval: 5000,
    navgation: true,
    pagination: true
}

function backCycle(num, cycle) {
    let index = num % cycle
    if (index < 0) {
        index += cycle
    }
    return index
}

export default ReactCarousel
export { TRANSITION_DURATION }
